package tictactoe;

public class Board {

	
	
	public static final char CROSS = 'X';
	public static final char NAUGHT = 'O';
	public static final char BLANK = '-';
	public static final byte CONTINUE = 1;
	public static final byte WIN = 2;
	public static final byte DRAWN = 3;
	
	private static final char[][] BLANKBOARD = {	{BLANK,BLANK,BLANK},
													{BLANK,BLANK,BLANK},
													{BLANK,BLANK,BLANK}};
	

	public static final short[][] LINEMAP = {	{1|32|128,	2|32, 		4|32|64},
												{1|16, 		2|128|64,	4|16},
												{1|8|64,	2|8,		4|8|128}};
	
	private char[][] currentBoard;
	
	private int lastx = -1, lasty = -1;
	
	public Board(){
		reset();
	}
	
	public void reset(){
		currentBoard = BLANKBOARD;
		lastx = -1; lasty = -1;
	}
	
	public char status(int x, int y){
		return currentBoard[x][y];
	}
	
	public int tryInsert(char symbol, int x, int y) throws SquareOccupiedException, InvalidSymbolException{
		int ret = 0;
		if (!validSymbol(symbol)) throw new InvalidSymbolException();
		if (currentBoard[x][y]!=BLANK) throw new SquareOccupiedException();
		
		//big switch statement
		short cells = LINEMAP[x][y];
		//row = 
		ret = evalWin(cells);
		
		place(symbol, x, y);
		lastx = x; lasty = y;
		
		return ret;
	}
	
	public byte place(char symbol, int x, int y) throws SquareOccupiedException, InvalidSymbolException{
		if (!validSymbol(symbol)) throw new InvalidSymbolException();
		if (currentBoard[x][y]!=BLANK) throw new SquareOccupiedException();
		
		currentBoard[x][y] = symbol;
		
		if (evalWin((short)255) > 0) return WIN;
		if (evalDraw()) return DRAWN;
		return CONTINUE;
	}
	
	//checks for win situation

	//returns number of winning rows (3 same symbols in a line)
	public int evalWin(short cells){
		int ret = 0;
		if((cells&1)>0)
			ret += evalLine(currentBoard[0][0],currentBoard[0][1],currentBoard[0][2]);
		if((cells&2)>0)
			ret += evalLine(currentBoard[1][0],currentBoard[1][1],currentBoard[1][2]);
		if((cells&4)>0)
			ret += evalLine(currentBoard[2][0],currentBoard[2][1],currentBoard[2][2]);
		
		if((cells&8)>0)
			ret += evalLine(currentBoard[0][2],currentBoard[1][2],currentBoard[2][2]);
		if((cells&16)>0)
			ret += evalLine(currentBoard[0][1],currentBoard[1][1],currentBoard[2][1]);
		if((cells&32)>0)
			ret += evalLine(currentBoard[0][0],currentBoard[1][0],currentBoard[2][0]);
		
		if((cells&64)>0)
			ret += evalLine(currentBoard[0][2],currentBoard[1][1],currentBoard[2][0]);
		if((cells&128)>0)
			ret += evalLine(currentBoard[0][0],currentBoard[1][1],currentBoard[2][2]);
		
		return ret;
	}
	
	//draw declared when all squares filled an no winner
	public boolean evalDraw(){
		//just check every cell, if we find an empty can't be a draw yet
		for(int i=0; i<3; i++)
			for(int k=0; k<3; k++)
				if(currentBoard[i][k]==BLANK) return false;
		return true;
	}
	
	
	public void clear(){
		currentBoard[lastx][lasty] = BLANK;
		lastx = -1; lasty = -1;
	}
	
	private boolean validSymbol(char x){
		return (x==NAUGHT) || (x==CROSS);
	}
	private short evalLine(char a, char b, char c){
		if(a==b && b==c) return 1;
		return 0;
	}
	
	public String toString(){
		String ret = "";
		for(int i=0; i<3; i++){
			for(int k=0; k<3; k++)
				ret+=currentBoard[k][i]+"\t";
			ret+="\n";
		}
		return ret;
	}
}
